Skip to content

docs(devx): check-react-page-adapter-contract names its class by shape, not by the records spelling, and re-anchors its citation (#15599) - #15770

Merged
baozhoutao merged 2 commits into
mainfrom
claude/issue-15599-page-adapter-header-shape
Sep 5, 2026
Merged

docs(devx): check-react-page-adapter-contract names its class by shape, not by the records spelling, and re-anchors its citation (#15599)#15770
baozhoutao merged 2 commits into
mainfrom
claude/issue-15599-page-adapter-header-shape

Conversation

@baozhoutao

Copy link
Copy Markdown
Contributor

Fixes #15599

Header-only edit on scripts/check-react-page-adapter-contract.mjs. Nothing this
gate does changes: no detector, no population, no verdict. #15094 ruled the
population stays (option D), and that fence is honoured literally — the proof is
below.

1. The class is named by SHAPE, not by the records spelling

The header's three worked instances are all spelled .records, and the header
(and the card family's titles) inherited that spelling as if it named the class.
It does not. The class is a union normalizer —
Array.isArray(x) ? x : x.LIMB applied to a find() result — and the limb it
reads is records in some members and data in others, with some members
carrying both. A reader who greps records sees a fraction of the class and
concludes it is a fraction of its real size.

2. The counts, re-measured on the branch base — and why they are a BAND

Re-derived on 66e68adc6 (this branch's base) from the #15094 census's prose
definition of its detector C, over the roots the census names (packages/** +
examples/**, source extensions, excluding node_modules / dist / .cache /
.turbo / coverage / build / .next). The harness is a throwaway; it is
NOT committed, exactly as the census's was not.

Method (the reading quoted in the header). On comment-, string-, template-
and regex-literal-masked source (offsets preserved), every Array.isArray(EXPR)
whose root identifier ID is also read as .records or .data — through an
optional TS cast, never across a statement or block boundary — inside the
innermost brace-balanced enclosing block, or inside EXPR itself.

blocks source test
union-normalizer blocks 142 98 44
limb records 71
limb data 82
both limbs 11

Files scanned: 5,694 — the same number the census reports, so the population
is the same population.

These differ from the card's numbers, and the PR carries mine. The census
(report 5547410463, at ca46f8f12) read 104 blocks: 41 records, 57 data,
6 both. Its harness was never committed, so the definition had to be re-derived
from prose — and four defensible readings of "the same brace-balanced enclosing
block" gave 69 / 116 / 142 / 164 blocks on ONE tree:

reading blocks records data both
bare-identifier subject only 69 45 33 9
+ member-expression subject, regex-masked 116 60 66 10
+ TS casts stripped (quoted above) 142 71 82 11
+ limb read anywhere in the statement 164 68 111 15

The 142 reading is the one quoted because it is the only one that reproduces
all four members the census names by path:
packages/verify/src/rls.ts, packages/rest/src/import-runner.ts,
packages/cli/src/utils/secret-reference-union.ts, and
packages/plugins/plugin-auth/src/phone-sms-texts.ts. Its precision is not
1.0 — spot-checking found at least one false positive
(packages/objectql/src/engine.ts, where Array.isArray(manifest.objectExtensions)
shares a block with an unrelated manifest.data), consistent with the census's
own measured 0.857 on the narrow route.

⚠️ So the header says the counts are a band, not a constant, and tells the next
reader to re-derive rather than trust the literal — the census report's own
warning (⛔ "do not close a stale-citation card by adding two more" stale
literals). What every reading agrees on is the load-bearing half: both limbs
are populous
, so the spelling cannot be the signal. Note the majority limb
flips between the narrowest reading and every wider one, which is itself the
argument for keying on shape.

3. The citation: de-lined to the repo's own anchor grammar

packages/client/src/index.ts:310
packages/client/src/index.ts#PaginatedResult.

The card's triage recommended de-lining over repointing, and the rot record
justifies it: the citation read :310 when written, the #15094 census found the
declaration at :392, triage read :390 the same day. On this base
grep -n 'PaginatedResult' packages/client/src/index.ts reports the declaration
at :390 — a cross-file line citation that moved twice inside one day.

Does a gate admit an anchor in a scripts/ header? No — checked, not
assumed. check-adr-symbol-anchors.mjs registers exactly one corpus,
defineCorpus({ id: 'adr', docRoots: [ADR_DIR], docPattern: /\.md$/ }) with
ADR_DIR = 'docs/adr'; grep -rn defineCorpus scripts/ finds no other
registration. So scripts/** is outside every symbol-anchor corpus, and nothing
resolves this anchor for you.

That is an argument about checking, not about spelling. The form used is the
repo's own authoritative grammar, scripts/symbol-anchors.mjs#ANCHOR_GRAMMAR,
whose last entry ends with this sentence, verbatim:

⛔ A LINE NUMBER IS NOT AN ANCHOR FORM.

(that entry leads with a placeholder path — DIR/FILE.ts:4901 with the
angle-bracket placeholders spelled as words here, since GitHub's body sanitizer
eats them; the same sentence appears again in that file's own prose header.)

A symbol name stays checkable by grep where a number does not, and the anchor is
forward-compatible the day a scripts/** corpus is registered. The header states
all of this beside the citation, including that nothing resolves it today.

⚠️ Declared deviation. The dispatch's literal fallback for "no gate admits
anchors in scripts/" was the current line number with a fragility note. This
PR de-lines instead, following the card's own alternative and triage's ⭐
recommendation, because a repointed number is the same defect with a fresher
value — triage's words: ⛔ "Repointing :310:390 closes this card for about
a day." Say the word and I will carry the number instead.

A second stale citation in the same sentence, fixed in the same edit

Three lines below, the same bullet cited content/docs/api/client-sdk.mdx:659
for the data?.records.map(...) sample. It is stale too:
grep -n 'records.map' content/docs/api/client-sdk.mdx puts it at :808;
:659 is now inside an unrelated VALIDATION_FAILED error-handling block. It is
now a file-level anchor, content/docs/api/client-sdk.mdx, with the code text
already quoted beside it (which is what makes it greppable).

This is the bounded in-place exemption, declared rather than slipped in: same
defect class as the card's, mechanically correct form pinned by the repo's own
anchor grammar, same file, no other claim on it, and no new verification surface
— all four conditions hold, so it is named here with its evidence rather than
filed as a card nobody would dispatch.

4. Proof the gate is byte-identical (⛔ no detector or population change)

Captured before the edit and again after, exit codes taken before any pipe:

node scripts/check-react-page-adapter-contract.mjs               → EXIT=0 (before and after)
node scripts/check-react-page-adapter-contract.mjs --self-test   → EXIT=0 (before and after)
diff before.txt after.txt                                        → EXIT=0 (no output)
diff before-selftest.txt after-selftest.txt                      → EXIT=0 (no output)

The two verdict lines, unchanged:

✓ check-react-page-adapter-contract: 21 app-showcase page module(s) + 1 content/docs react-page sample(s) (from 396 doc file(s), 1958 fenced block(s)) — every adapter query option is $-prefixed, every row read is off `data`, and no find() result is tested for array-ness.
✓ check-react-page-adapter-contract --self-test: 51 assertions — all THREE detectors observed FIRING and observed silent, the `Array.isArray` limb pinned on the three lines #13969 deleted (the docs one on the very string `recordsReads` is pinned to IGNORE), the selector observed refusing the engine.find / useQuery / webhook shapes it must not fabricate on, and an empty sweep of EITHER half observed failing the census.

The diff is comments only. The dispatch's non-comment probe

git diff -U0 origin/main -- scripts/check-react-page-adapter-contract.mjs \
  | grep -E '^[-+]' | grep -vE '^(\+\+\+|---)' | grep -vE '^[-+]\s*(//|\*|/\*)'

prints nothing — 0 bytes.

5. Gates — all 29 derived commands run at HEAD 0b6f4bd1d

Derived with node scripts/pm/dispatch-gates.mjs --changed --commands --repo objectstack-ai/objectstack
(exit 0; the tool took the change set from git itself, 1 path). Every command
run, exit code captured before any pipe:

exit command
⊘ 3 node packages/lint/scripts/check-reference-carrier-shape.mjs
⊘ 3 node packages/lint/scripts/check-reference-carrier-shape.mjs --self-test
⊘ 3 node scripts/check-ci-filter-parity.mjs
⊘ 3 node scripts/check-closing-keyword-parity.mjs
⊘ 3 node scripts/check-closing-keyword-parity.mjs --self-test
⊘ 1 node scripts/check-comment-mask-corpus.mjs
✅ 0 node scripts/check-declaration-mirrors.mjs
✅ 0 node scripts/check-declaration-mirrors.mjs --self-test
✅ 0 node scripts/check-self-test-wired.mjs
✅ 0 node scripts/check-self-test-wired.mjs --self-test
✅ 0 node scripts/check-self-test-workflow-commands.mjs
✅ 0 node scripts/check-self-test-workflow-commands.mjs --self-test
✅ 0 node scripts/check-whole-set-label-write.mjs
✅ 0 node scripts/check-whole-set-label-write.mjs --self-test
✅ 0 node scripts/pm/bare-root-worklist.mjs --self-test
✅ 0 pnpm check:agent-test-spelling
✅ 0 pnpm check:bash32-floor
✅ 0 pnpm check:cli-command-ids
✅ 0 pnpm check:cross-package-test-inputs
⊘ 3 pnpm check:driver-memory-census
✅ 0 pnpm check:entry-guard
✅ 0 pnpm check:nul-bytes
✅ 0 pnpm check:parse-guard
✅ 0 pnpm check:pm-dispatch-gates
✅ 0 pnpm check:pnpm-filter-targets
✅ 0 pnpm check:ratchet-remedy-authority
✅ 0 pnpm check:react-page-adapter-contract
✅ 0 pnpm check:refd-timer-probe
✅ 0 pnpm check:watch-hint-literal

node scripts/pm/check-governed-merges.mjs --test scripts/check-react-page-adapter-contract.mjs,
run on the final file list, exit 0:

governed-surface predicate: 0 of 1 path(s) hit the register (5 surfaces, repo-agnostic).
  ✅  NOT governed — ordinary queue landing applies to a PR with exactly this file list.

⊘ NOT MEASURED, by name

22 of 29 exit 0. The other 7 never entered a gate body: six exit 3 with
their own words, PREREQUISITE NOT MET, and one exits 1 on
ERR_MODULE_NOT_FOUND at import time. This worktree has no node_modules, so
these are neither failures nor clearances — CI measures them:

  • node packages/lint/scripts/check-reference-carrier-shape.mjs — ⊘ NOT MEASURED: PREREQUISITE NOT MET — the dependency typescript is not installed
  • node packages/lint/scripts/check-reference-carrier-shape.mjs --self-test — ⊘ NOT MEASURED: PREREQUISITE NOT MET — the dependency typescript is not installed
  • node scripts/check-ci-filter-parity.mjs — ⊘ NOT MEASURED: PREREQUISITE NOT MET — the dependency yaml is not installed
  • node scripts/check-closing-keyword-parity.mjs — ⊘ NOT MEASURED: PREREQUISITE NOT MET — the dependency yaml is not installed
  • node scripts/check-closing-keyword-parity.mjs --self-test — ⊘ NOT MEASURED: PREREQUISITE NOT MET — the dependency yaml is not installed
  • node scripts/check-comment-mask-corpus.mjs — ⊘ NOT MEASURED: ERR_MODULE_NOT_FOUND — @typescript-eslint/parser (never entered the gate body)
  • pnpm check:driver-memory-census — ⊘ NOT MEASURED: PREREQUISITE NOT MET — the dependency typescript is not installed

Plus the three families dispatch-gates itself reports as taking a value from
the workflow (no value outside a CI run):
check-cross-package-test-inputs.mjs --union-into "$RUNNER_TEMP/…",
check-shard-attestation.mjs --shard a matrix variable, and
check-test-completeness.mjs "$RUNNER_TEMP/test-core.log".

6. Filed, not fixed here

#15765 — no symbol-anchor corpus covers scripts/**, so the 27 cross-file
path:NNN citations across 14 scripts/**/*.mjs files rot unchecked. This
card's two are the worked example; the general repair is a defineCorpus call
plus a migration, and it needs a measurement this card does not owe (whether the
extractor reads // comment blocks cleanly). Filed bare with finding,
no assignee.

7. Changeset

skip-changeset. AGENTS.md, Post-Task Checklist §3: ⛔ "never skip-changeset:
that label is for a diff that publishes nothing from any released package." This
diff is comment lines in one repo-root tooling script under scripts/, which no
package publishes.

8. Channel switch, declared

REST writes are unavailable in this seat. POST /repos/objectstack-ai/objectstack/issues
was refused before it left the box (tool-policy denial, not a GitHub status), while
repo-scoped REST reads answer 200 all session and git push works. The GitHub
search endpoint answers 403 with its own words: This GitHub API path is not available: sessions are bound to their configured repositories. So this PR, the
report comment and #15765 were written through MCP, and the one dedup search
before filing #15765 was a single targeted search_issues. MCP call count for
the whole run is in the os-dev-report comment on #15599.


🤖 Generated with Claude Code

https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk


Generated by Claude Code

…tions

`check-react-page-adapter-contract`'s header keyed the union-normalizer class
on the `records` spelling, which is the minority limb: the class is the SHAPE
`Array.isArray(x) ? x : x.<limb>` on a `find()` result, and both `records` and
`data` limbs are populous (some blocks carry both). Records that, with the
counts re-measured on this base and the band across readings disclosed, so the
numbers are not the next stale literal.

Also repoints the two stale cross-file line citations in the same header to the
repo's own anchor grammar: `packages/client/src/index.ts:310` (the declaration
moved to `:392`, then `:390`, inside one day) becomes
`packages/client/src/index.ts#PaginatedResult`, and `client-sdk.mdx:659` (the
sample is at `:808`) becomes a file-level anchor.

Header-only. No detector or population change: the gate's verdict and
`--self-test` output are byte-identical before and after.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
The de-lining paragraph quoted `client-sdk.mdx`'s current line as evidence of
drift, which would have made this edit add the very thing it removes: a live
cross-file line number nothing derives. The historical numbers stay as a dated
rot record and now say so.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
@claude

claude Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

ACCEPT — PR #15770 (head 0b6f4bd1d, scripts/check-react-page-adapter-contract.mjs +54/−3) reviewed against the GitHub three-dot diff, not the report.

Header-only, as ruled: the class is named by SHAPE with both limbs measured on the base (142 blocks: 71 records / 82 data / 11 both — re-derived with a stated method and a sensitivity band, not the census's digits), the PaginatedResult citation is de-lined to the symbol-anchor form, and the second stale citation in the same sentence (client-sdk.mdx sample, now :808) is repaired under the bounded exemption and named. No population change (#15094 D).

Ruling on the open question: A — keep the symbol anchor packages/client/src/index.ts#PaginatedResult. The fallback in the brief was for the case where no gate admits anchors in scripts/, and that case holds (scripts/** is in no symbol-anchor corpus, stated in the header) — but the repo's own ANCHOR_GRAMMAR, the card and triage all name de-lining as the outcome, and B re-adds the literal this card removes (it moved :310:392:390 in one day). The rot class itself is now #15765 (dev-filed, bare).

Measured by this seat: non-comment diff 0 lines; plain output and --self-test output of the branch blob vs main's — byte-IDENTICAL (diff exit 0 both; ✓ check-react-page-adapter-contract --self-test: 51 assertions …); PaginatedResult declared at packages/client/src/index.ts:390; client-sdk.mdx:808 carries the data?.records.map(…) sample; git merge-tree --write-tree origin/main <branch> → EXIT=0; governed test per the report NOT governed. NOT MEASURED here: the yaml / typescript / @typescript-eslint/parser gates by name.

Channel note recorded, not penalised: REST POST /issues and PR creation were refused in the dev's box, so issue/PR creation went through MCP (5 calls, declared); the report comment went through REST.

Flip + arm when both required jobs report success on 0b6f4bd1d.


Generated by Claude Code

@claude

claude Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Flipped ready + auto-merge enabled (07:24Z, method: MERGE). Required jobs on 0b6f4bd1d: Lint & Repo Gates = success, TypeScript Type Check = success; git merge-tree --write-tree origin/main <branch> → EXIT=0 against the current main. Watched; on landing #15599 closes.


Generated by Claude Code

@baozhoutao
baozhoutao added this pull request to the merge queue Sep 5, 2026
Merged via the queue into main with commit 901773b Sep 5, 2026
36 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-15599-page-adapter-header-shape branch September 5, 2026 08:06
baozhoutao pushed a commit that referenced this pull request Sep 5, 2026
…re its held allowance row (#15765)

The `scripts/**` symbol-anchor corpus (#15806) landed with two dated
`HELD_FILE_ALLOWANCES` rows for files live PRs held. PR #15770 landed, so the
row for `scripts/check-react-page-adapter-contract.mjs` is free — and an
allowance nobody retires is an exemption wearing a date.

The four dated readings in that gate's rot-record paragraph are now stated as
DATA — a small table with the file and the line number in separate cells —
never in `path:NNN` anchor form. The NUMBERS ARE NOT REPAIRED OR REPOINTED:
they are readings taken on a date, the paragraph's argument is unchanged, and
its ⛔ line still declares every number a record rather than a pointer. The one
substantive addition is that the paragraph no longer claims nothing resolves
citations in `scripts/**` — since #15806 something does, which is why the
anchor spelling had to go.

The self-test battery floor moves 34 → 30 because four of its cases are
registered PER allowance row; the reason is recorded next to the number so a
later reader cannot mistake the drop for cases that stopped running.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants